import os
import sys
import importlib.util

class ResponseHandlers(object):
    def __init__(self, env):
        self.events = {}
        self.scan_exceptions = env["SCAN_EXCEPTIONS"] if "SCAN_EXCEPTIONS" in env else []
        if not isinstance(self.scan_exceptions, list):
            self.scan_exceptions = [self.scan_exceptions]

    def register(self, event_name:str, event_handler:callable, required_params:list):
        self.events.update({
            event_name: { 
                "handler": event_handler,
                "required_params": required_params,
            }
        })
        return self

    def check(self, event_name:str, data:dict):
        required_params = self.events[event_name]["required_params"]
        for item in required_params:
            if isinstance(item, str):
                if item not in data:
                    raise Exception(f"Event '{ event_name }' require parameters: '{ str(required_params) }'.")
            if isinstance(item, dict):
                if "name" not in item or "type" not in item:
                    raise Exception(f"Event '{ event_name }' `required_params` dictionary required two items: `name` and `type`.")
                if item["name"] not in data:
                    raise Exception(f"Event '{ event_name }' require parameters: '{ str(required_params) }'.")
                if not isinstance(data[item["name"]], item["type"]):
                    raise Exception(f"Event '{ event_name }' parameter '{ item['name'] }' required data type: '{ str(item['type']) }'.")

    def get(self, event_name:str):
        return self.events[event_name]["handler"] if event_name in self.events else None

    def scan(self, path:str):
        sys.path.append(path)
        for item in os.listdir(path):
            if item not in self.scan_exceptions and item.endswith(".py"):
                event_name = item[:-3]
                event_handler = importlib.import_module(event_name)
                self.register(
                    event_name,
                    event_handler.handler,
                    event_handler.required_params if "required_params" in dir(event_handler) else []
                )
        sys.path.remove(path)
        return self